package com.introspy.hooks; import com.introspy.core.IntroHook; import java.security.Key; import java.util.Stack; import javax.crypto.Cipher; import android.util.Log; import com.introspy.core.ApplicationConfig; class Intro_CRYPTO extends IntroHook { protected static Cipher _lastCipher; protected static Integer _lastMode; } class Intro_CRYPTO_FINAL_UTIL extends Intro_CRYPTO { protected static Stack<byte[]> IVList = new Stack<byte[]>(); protected String _out = ""; protected boolean _warning = false; protected void _getIV(Cipher cipher) { if (cipher.getIV() != null) { String iv = _getReadableByteArr(cipher.getIV()); _out += "; IV: " + iv; _logParameter("IV", iv); if (cipher.getIV()[0] == 0) { Log.w("Introspy", "!!! IV of 0"); _warning = true; } else { // check if this IV has already been used if (IVList.contains(cipher.getIV())) { _out += " - !!! Static IV"; _warning = true; } IVList.push(cipher.getIV()); // keep a list of a max of 10 IVs if (IVList.size() > 10) IVList.pop(); } } } protected void _getAlgo(Cipher cipher) { String algo = cipher.getAlgorithm(); if (algo != null) { _out = "-> Algo: " + algo; _logParameter("Algo", algo); if (cipher.getAlgorithm().contains("ECB")) { _warning = true; _out += " - !!! ECB used. ECB mode is broken and should not be used."; } } } } class Intro_CRYPTO_FINAL extends Intro_CRYPTO_FINAL_UTIL { private void _getInput(byte[] data) { if (data != null && data.length != 0) { // when no args to doFinal (used only update()) String i_sdata = null; i_sdata = new String(data); if (i_sdata != null && !i_sdata.isEmpty()) { if (_isItReadable(i_sdata)) { i_sdata = _byteArrayToReadableStr(data); _logParameter("input (Encrypt)", i_sdata); _logLine("-> ENCRYPT: [" + i_sdata + "]"); } else { String sdata = _byteArrayToB64(data); _logLine("-> Input data is not in a readable format, " + "base64: ["+ sdata +"]"); _logParameter("Output (converted to b64)", sdata); } } } } private void _getOutput(Object... args) { byte[] data = null; String o_sdata = null; // if (cipher == _lastCipher && _lastMode == Cipher.DECRYPT_MODE) try { data = (byte[]) _hookInvoke(args); } catch (Throwable e) { Log.i(_TAG_ERROR, "doFinal function failed: "+e); } if (data != null) { o_sdata = new String(data); if (_isItReadable(o_sdata)) { o_sdata = _byteArrayToReadableStr(data); _logParameter("Ouput (Decrypt)", o_sdata); _logLine("-> DECRYPT: [" + o_sdata + "]"); } else { String sdata = _byteArrayToB64(data); _logLine("-> Output data is not in a readable format," + " base64: ["+ sdata +"]"); _logReturnValue("Output (converted to b64)", sdata); } } // } else { // } } public void execute(Object... args) { if (_resources != null) { _warning = false; _out = ""; Cipher cipher = (Cipher) _resources; _logBasicInfo(); // input if (args.length != 0 && args[0] != null) { try { _getInput((byte[]) args[0]); } catch (Exception e) { Log.w(_TAG_ERROR, "Error in _getInput " + "(CRYPTO_IMPL->dofinal): " + e); } } //output try { _getOutput(args); } catch (Exception e) { Log.w(_TAG_ERROR, "Error in _getOutput " + "(CRYPTO_IMPL->dofinal): " + e); } // algo/IV try { _getAlgo(cipher); _getIV(cipher); } catch (Exception e) { Log.w(_TAG_ERROR, "Error in _getAlgo/_getCipher " + "(CRYPTO_IMPL->dofinal): " + e); } // dump some params if (cipher.getParameters() != null && ApplicationConfig.g_debug) _logLine("Parameters: " + cipher.getParameters()); if (_warning) _logFlush_W(_out); else if (!_out.isEmpty()) _logFlush_I(_out); } else { Log.w(_TAG_ERROR, "Error in Intro_CRYPTO: resource is null"); } } } class Intro_CRYPTO_INIT extends Intro_CRYPTO { public void execute(Object... args) { // let's not care about init since we are hooking // the key class already // BUT it can be useful to get a state of the mode // if needed later if (_resources != null) { try { _lastCipher = (Cipher) _resources; // get the mode Integer mode = _lastMode = (Integer) args[0]; String smode; switch (mode) { case Cipher.DECRYPT_MODE: smode = "DECRYPT_MODE"; break; case Cipher.ENCRYPT_MODE: smode = "ENCRYPT_MODE"; break; default: smode = "???"; } _logBasicInfo(); String out = "-> Mode: " + smode; // get the key Key key = (Key) args[1]; String skey = ""; if (key != null) { skey = _getReadableByteArr(key.getEncoded()); out += ", Key format: " + key.getFormat() + ", Key: [" + skey + "]"; } _logParameter("Mode", smode); _logParameter("Key", skey); _logParameter("Key Format", key.getFormat()); _logFlush_I(out); } catch (Exception e) { Log.w(_TAG_ERROR, "Error in Intro_CRYPTO: " + e); } } } }